package vg.modules.search.components;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import vg.core.VisualGraph;
import vg.core.graph.GraphNode;
import vg.core.plugin.PluginParameter;
import vg.core.storableGraph.StorableAttribute;
import vg.core.storableGraph.StorableSubGraph;
import vg.core.storableGraph.StorableVertex;
import vg.modules.search.SearchPanelModel;
import com.almworks.sqlite4java.SQLiteException;
import com.almworks.sqlite4java.SQLiteStatement;
/**
* This class realizes first panel for search panel.
* @author tzolotuhin
*/
public class FirstPanel {
private final JPanel view;
private final ConditionalPanel conditionalPanel;
private final PluginParameter parameter;
private StorableSubGraph currentStorableSubGraph;
//interface components
private final JLabel chooseGraphLabel;
private final GraphComboBox graphComboBox;
private GraphNode rootNode = null; // root node
private Set<Integer>selectedVertexIdList = null; // selected vertex id's
private List<Integer>currentViewIds; // if search panel work for current graph view
private Set<String>vertexAttributes;
private SearchPanelModel model;
/**
* Constructor.
* @param parameter - connection with model and user interface.
* @param searchPanel - feedback with search panel.
*/
public FirstPanel(final PluginParameter parameter, final SearchPanelModel model) {
this.parameter = parameter;
this.model = model;
this.view = new JPanel(new GridBagLayout());
this.conditionalPanel = new ConditionalPanel();
//create graph chooser
this.chooseGraphLabel = new JLabel("Choose graph :");
GridBagConstraints gbc = new GridBagConstraints(0,0, 1,1, 0,0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 10, 5, 0), 0,0);
this.view.add(this.chooseGraphLabel, gbc);
this.graphComboBox = new GraphComboBox();
this.graphComboBox.addItem(GraphComboBox.DEF_VIEW, null, "Current selection graph");
gbc = new GridBagConstraints(1,0, 1,1, 1,0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 10), 0,0);
this.view.add(this.graphComboBox.getView(), gbc);
this.graphComboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectedItemInGraphComboBox(true);
}
});
//add split pane between conditional panel and additional panel
gbc = new GridBagConstraints(0,1, 2,1, 1,1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0,0);
this.view.add(this.conditionalPanel.getView(), gbc);
}
/**
* This method adds new graph (name and id).
* @param id - id of graph in main storage.
* @param name - name of graph (only for user).
*/
public synchronized void addGraph(final int id, final String name) {
if(id >= 0 && name != null) {
this.graphComboBox.addItem(GraphComboBox.DEF_GRAPH, id, name);
}
}
public synchronized void reset() {
while(this.graphComboBox.getItemCount() > 1) {
this.graphComboBox.removeItem(1);
}
}
/**
* This method sets current storable subgraph.
* @param ssg - current storable subgraph.
*/
public synchronized void setCurrentSubGraph(final StorableSubGraph ssg) {
this.currentStorableSubGraph = ssg;
int type = this.graphComboBox.getSelectedType();
if(type == GraphComboBox.DEF_VIEW) {
selectedItemInGraphComboBox(false);
}
}
/**
* This method updates user interface.
*/
public synchronized void updateUITheme() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SwingUtilities.updateComponentTreeUI(FirstPanel.this.view);
}
});
this.conditionalPanel.updateUITheme();
}
public synchronized Set<Integer> getSelectedVertexIdList() {
return(this.selectedVertexIdList);
}
public synchronized GraphNode getRootNode() {
return(this.rootNode);
}
public synchronized Set<String> getVertexAttributes() {
return(this.vertexAttributes);
}
public synchronized JPanel getView() {
return(this.view);
}
/**
* This method builds tree.
*/
public synchronized void search() {
// search vertexes
int type = this.graphComboBox.getSelectedType();
int id = -1;
if(type == GraphComboBox.DEF_VIEW) {
if(this.currentStorableSubGraph == null) return;
List<StorableVertex> lsv = this.currentStorableSubGraph.getVertices();
if(lsv == null) return;
StorableVertex sv = lsv.get(0);
if(sv == null) return;
int vsi = sv.getStorableId();
String request = "select s1.db_id_graph " +
"from com_graph_subgraph s1, com_subgraph_vertex s2 " +
"where s2.db_id_subgraph = s1.db_id_subgraph and s2.db_id_vertex = " + Integer.valueOf(vsi).toString() + ";";
List<List<Object>> result = this.parameter.model.executeSQLRequest(request);
if(result != null) {
if(!result.isEmpty()) {
id = (Integer)result.get(0).get(0);
}
}
} else if(type == GraphComboBox.DEF_GRAPH) {
id = (Integer)this.graphComboBox.getSelectedObject();
}
// build request
String request = "select distinct v.db_id_vertex " +
"from com_graph_subgraph cgs, com_subgraph_vertex v " +
"where cgs.db_id_graph = " + Integer.valueOf(id).toString() +
" and cgs.db_id_subgraph = v.db_id_subgraph ";
String innerRequest = this.conditionalPanel.getRequest("v.db_id_vertex", 0);
if(innerRequest.length() > 0) {
request += " and (";
}
request += innerRequest;
if(innerRequest.length() > 0) {
request += ");";
} else {
request += ";";
}
List<List<Object>> result = this.parameter.model
.executeSQLRequest(request);
if (result != null) {
this.selectedVertexIdList = new HashSet<Integer>();
Iterator<List<Object>> it = result.iterator();
while (it.hasNext()) {
Integer db_id = (Integer)it.next().get(0);
this.selectedVertexIdList.add(db_id);
}
// get graph skeleton
this.rootNode = this.parameter.model.getGraphSkeleton(id);
if (this.rootNode != null && type == GraphComboBox.DEF_VIEW) {
this.rootNode.removeNodes(this.currentViewIds);
}
} else {
VisualGraph.windowMessage.errorMessage(
"Can't execute SQL request.", "Search panel error");
}
}
///////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
///////////////////////////////////////////////////////////////////////////
/**
* This method selects item in comboBox and updates all components.
*/
private void selectedItemInGraphComboBox(final boolean flag) {
int type = this.graphComboBox.getSelectedType();
if(type == GraphComboBox.DEF_VIEW) {
if(flag) this.model.updateWorkView();
if(this.currentStorableSubGraph != null) {
// find all attributes in current selection subgraph
Map<String, Set<String>>dataAttributes = new HashMap<String, Set<String>>();
Set<Integer>innerIds = new HashSet<Integer>();
this.currentViewIds = new ArrayList<Integer>();
this.vertexAttributes = new HashSet<String>();
for(StorableVertex bufVertex : this.currentStorableSubGraph.getVertices()) {
if(bufVertex.getInnerGraph() != null) {
innerIds.add(bufVertex.getInnerGraph());
}
List<StorableAttribute>sal = bufVertex.getAttributes();
this.currentViewIds.add(bufVertex.getStorableId());
if(sal != null) {
for(StorableAttribute bufAttr : sal) {
if(bufAttr.getName() != null && bufAttr.getValue() != null) {
Set<String>value = dataAttributes.get(bufAttr.getName());
if(value == null) {
value = new HashSet<String>();
dataAttributes.put(bufAttr.getName(), value);
}
value.add(bufAttr.getValue());
this.vertexAttributes.add(bufAttr.getName());
} else {
VisualGraph.log.printError("[" + this.getClass().getName() + ".selectedItemInGraphComboBox]" + " [BAD] Error in search panel. Attribute name or attribute value = null(Vertex)");
}
}
}
} // end of vertex cycle
// find attributes in inner graphs
while(true) {
Set<Integer>bufInnerIds = new HashSet<Integer>();
for(Integer bufId : innerIds) {
// select attributes
String request = "select a.name, a.value " +
"from attribute a, com_subgraph_vertex csv, com_vertex_attribute cva " +
"where csv.db_id_subgraph = " + bufId.toString() +
" and csv.db_id_vertex = cva.db_id_vertex " +
" and cva.db_id_attribute = a.db_id;";
List<List<Object>> result = this.parameter.model
.executeSQLRequest(request);
if (result != null) {
Iterator<List<Object>> it = result.iterator();
while (it.hasNext()) {
List<Object> next = it.next();
String name = (String) next.get(0);
String value = (String) next.get(1);
Set<String> buf = dataAttributes.get(name);
if (buf != null) {
if (!buf.contains(value)) {
buf.add(value);
}
} else {
Set<String> a = new HashSet<String>();
a.add(value);
dataAttributes.put(name, a);
}
this.vertexAttributes.add(name);
}
}
// select inner graph IDs
request = "select v.db_id, v.db_id_inner_graph " +
"from com_subgraph_vertex csv, vertex v " +
"where csv.db_id_subgraph = " + bufId.toString() +
" and csv.db_id_vertex = v.db_id;";
result = this.parameter.model.executeSQLRequest(request);
if (result != null) {
Iterator<List<Object>> it = result.iterator();
while (it.hasNext()) {
List<Object> next = it.next();
Integer vid = (Integer) next.get(0); // vertex id
this.currentViewIds.add(vid);
Integer igid = (Integer) next.get(1); // inner graph id
if (igid != null) {
bufInnerIds.add(igid);
}
}
}
}
if(bufInnerIds.size() == 0) {
break;
} else {
innerIds = bufInnerIds;
}
}
this.conditionalPanel.setNewDataAttributes(dataAttributes);
this.model.setSearchActive(true);
} else {
this.model.setSearchActive(false);
}
} else if(type == GraphComboBox.DEF_GRAPH) {
Integer id = (Integer)this.graphComboBox.getSelectedObject();
if(id == null) {
VisualGraph.log.printError("[" + this.getClass().getName() + ".SearchPanel] Id of graph = null");
return;
}
//build request for data base
String request = "select s1.name, s1.value " +
"from attribute s1, com_graph_subgraph s2, com_subgraph_vertex s3, com_vertex_attribute s4 " +
"where s2.db_id_graph = " + id.toString() +
" and s2.db_id_subgraph = s3.db_id_subgraph " +
" and s3.db_id_vertex = s4.db_id_vertex " +
" and s4.db_id_attribute = s1.db_id;";
Map<String, Set<String>> dataAttributes = new HashMap<String, Set<String>>();
List<List<Object>> result = this.parameter.model
.executeSQLRequest(request);
if (result != null) {
Iterator<List<Object>> it = result.iterator();
while (it.hasNext()) {
List<Object> next = it.next();
String name = (String)next.get(0);
String value = (String)next.get(1);
Set<String> buf = dataAttributes.get(name);
if (buf != null) {
if (!buf.contains(value)) {
buf.add(value);
}
} else {
Set<String> a = new HashSet<String>();
a.add(value);
dataAttributes.put(name, a);
}
}
}
this.conditionalPanel.setNewDataAttributes(dataAttributes);
this.model.setSearchActive(true);
}
}
}